#pragma once
#include"Comm.hpp"
#include<iostream>
#include<string.h>
#include<error.h>
#include<string>
#include<unistd.h>
#include<functional>


namespace nt_server
{
    const uint16_t default_port=8888;
    const int backlog=32;

    using func_t=std::function<std::string(std::string)>;


    class TcpServe
    {
         //业务处理
        void Service(int sock,const std::string& clientip,const uint16_t& clientport)
        {   
            char buff[1024];
            std::string who=clientip+"-"+std::to_string(clientport);
            while(true)
            {
                ssize_t n=read(sock,buff,sizeof(buff)-1);
                if(n>0)
                {
                    //读取成功
                    buff[n]='\0';
                    std::cout<<"Server get:"<<buff<<"from"<<who<<std::endl;

                    std::string respond=_func(buff);

                    //发送给服务器
                    write(sock,buff,strlen(buff));
                }
                else if(n==0)
                {
                    //写端关闭，读取结束
                    std::cout<<"Client"<<who<<" "<<sock<<"quit"<<std::endl;
                    close(sock);
                    break;
                }
                else{
                    //读取出错
                    perror("Read Fail");
                    close(sock);
                    break;
                }
            }
        }
    public:
        TcpServe(const func_t& func,const uint16_t port=default_port)
        :_func(func)
        ,_port(port)
        ,_quit(false)
        {
        }

        ~TcpServe()
        {

        }

        void InitServe()
        {
            //创建套接字
            _listensock=socket(AF_INET,SOCK_STREAM,0);
            if(_listensock==-1)
            {
                std::cerr<<"Create socket Falie"<<strerror(errno)<<std::endl;
                exit(SOCKET_ERR);
            }
                std::cout<<"Create socket Success "<<_listensock<<std::endl;
            
            //绑定套接字
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));
            local.sin_family=AF_INET;
            local.sin_addr.s_addr=INADDR_ANY;
            local.sin_port=htons(_port);
            
            //成功返回0，失败返回-1，并设置errno值
            if(bind(_listensock,(const sockaddr*)&local,sizeof(local)))
            {
                std::cerr<<"Bind Fail"<<strerror(errno)<<std::endl;
                exit(BIND_ERR);
            }

            //监听,成功返回0，失败返回-1,并设置errno变量
            if(listen(_listensock,backlog))
            {
                perror("listen fali");
                exit(LISTEN_ERR);
            }
            std::cout<<"listen success"<<std::endl;
        }

        void StartServe()
        {
            while(!_quit)
            {
                //1.处理连接请求
                struct sockaddr_in client;
                socklen_t len=sizeof(client);

                //accept成功返回新的文件描述符，失败返回-1，并设置errno
                int newsock=accept(_listensock,(sockaddr*)&client,&len);
                
                //2.如果连接失败继续请求
                if(newsock==-1)
                {
                    perror("Accept Fail");
                    continue;
                }

                //连接成功，获取客户端信息
                std::string clientip=inet_ntoa(client.sin_addr);
                uint16_t clientport=ntohs(client.sin_port);

                std::cout<<"Server accept"<<clientip<<"-"<<clientport<<" "<<newsock<<"from"<<_listensock<<std::endl;
                
                //3.准备通过newsock进行通信
                Service(newsock,clientip,clientport);
            }
        }

       

    private:
        uint16_t _port;
        int _listensock;
        bool _quit;
        func_t _func;
    };
}